package cn.allin.me.enums;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;

/**
 * 枚举工具类
 *
 * @author turboj 2022/11/28 下午10:22
 */
public class EnumUtils {

    private static final Map<String, Enum<? extends IdAndNameEnum<? extends Serializable>>[]> ENUM_MAP = new HashMap<>();

    public static <E extends Enum<? extends IdAndNameEnum<V>>, V extends Serializable> boolean exists(Class<E> enumClass, V id) {
        E[] values = getEnumValues(enumClass);
        for (E e : values) {
            IdAndNameEnum<V> value = (IdAndNameEnum<V>) e;
            if (Func.equals(id, value.getId())) {
                return true;
            }
        }
        return false;
    }

    public static <E extends Enum<? extends IdAndNameEnum<V>>, V extends Serializable> void requireExists(Class<E> enumClass, V id, String message) {
        if (!exists(enumClass, id)) {
            throw new RuntimeException(message);
        }
    }

    public static <E extends Enum<? extends IdAndNameEnum<V>>, V extends Serializable> E getEnumById(Class<E> enumClass, V id) {
        Enum<? extends IdAndNameEnum<V>>[] values = getEnumValues(enumClass);
        for (Enum<? extends IdAndNameEnum<V>> value : values) {
            if (Func.equals(id, ((IdAndNameEnum<V>) value).getId())) {
                return (E) value;
            }
        }
        return null;
    }

    public static <E extends Enum<? extends IdAndNameEnum<V>>, V extends Serializable> String getNameById(Class<E> enumClass, V id) {
        E value = getEnumById(enumClass, id);
        return Func.isNotNull(value, new Supplier<String>() {
            @Override
            public String get() {
                return ((IdAndNameEnum<V>) value).getName();
            }
        });
    }

    public static <E extends Enum<? extends IdAndNameEnum<V>>, V extends Serializable> V getIdByName(Class<E> enumClass, String name) {
        E[] values = getEnumValues(enumClass);
        for (E e : values) {
            IdAndNameEnum<V> value = ((IdAndNameEnum<V>) e);
            if (name.equals(value.getName())) {
                return value.getId();
            }
        }
        return null;
    }

    private static <E extends Enum<? extends IdAndNameEnum<V>>, V extends Serializable> E[] getEnumValues(Class<E> enumClass) {
        String hashkey = enumClass.getName();
        if (ENUM_MAP.containsKey(hashkey)) {
            return (E[]) ENUM_MAP.get(hashkey);
        } else {
            E[] values = enumClass.getEnumConstants();
            ENUM_MAP.put(hashkey, values);
            return values;
        }
    }

}